﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Fsb.Utility;

namespace VideoCache.Spider.FileFetchers
{
    class QQFetcher : IFetcher
    {
        const string JSON_URL = "http://vv.video.qq.com/getinfo?platform=11&otype=json&vids={0}&defaultfmt={1}";
        const string KEY_URL = "http://vv.video.qq.com/getkey?vt={0}&vid={1}&format={2}&otype=json&filename={3}&platform=11";

        public FetcherResult[] GetFiles(string url)
        {
            string html = HttpUtility.Get(url, Encoding.UTF8);

            string vid = this.GetVid(html);

            QQData data = this.GetQQData(vid, string.Empty);

            List<FetcherResult> list = new List<FetcherResult>();

            foreach (Fi fi in data.Fl.Fi)
            {
                if (fi.Name != "flv")
                {
                    QQData item = this.GetQQData(vid, fi.Name);

                    FetcherResult result = this.GetResult(item);

                    if (result != null)
                    {
                        switch (fi.Name.ToLower())
                        {
                            case "sd":
                                result.Resolution = Resolution.Level_1;
                                break;
                            case "hd":
                                result.Resolution = Resolution.Level_2;
                                break;
                            case "shd":
                                result.Resolution = Resolution.Level_3;
                                break;
                            //case "fhd":   // 不给出全高清结果
                            //    result.Resolution = Resolution.Level_4;
                            //    break;
                            // flv 是QQ视频的单文件格式，清晰度为高清
                            //case "flv":
                            //    break;
                        }
                        list.Add(result);
                    }
                }
            }

            if (list.Count == 0)
            {
                throw new FetcherException("无法获取视频下载地址，视频不存在或已删除。");
            }

            return list.ToArray();
        }

        private FetcherResult GetResult(QQData item)
        {
            if (item.Vl.Vi.Length > 0)
            {
                Vi vi = item.Vl.Vi[0];

                if (vi.Ul.Ui.Length > 0)
                {
                    FetcherResult result = new FetcherResult();

                    Fi currentFi = null;
                    foreach (Fi fi in item.Fl.Fi)
                    {
                        if (fi.Sl == 1)
                        {
                            currentFi = fi;
                            break;
                        }
                    }

                    string fileName = Path.GetFileNameWithoutExtension(vi.Fn);
                    string exeName = Path.GetExtension(vi.Fn);

                    // 特殊处理,qq视频有一个单文件可以提供下载的，但是仅仅是高清模式，暂时不提供下载
                    if (vi.Cl.Ci != null)
                    {
                        foreach (Ci ci in vi.Cl.Ci)
                        {
                            string singleFileName = string.Format("{0}.{1}{2}", fileName, ci.Idx, exeName);
                            Ui ui = vi.Ul.Ui[1];
                            QQKey keyData = this.GetKey(vi.Vid, ui.Vt, currentFi.Id, singleFileName);

                            string url = ui.Url + singleFileName + "?vkey=" + keyData.Key;
                            result.Files.Add(url);
                        }

                        return result;
                    }
                }
            }

            return null;
        }

        private QQKey GetKey(string vid, int vt, int fiId, string filename)
        {
            string json = HttpUtility.Get(string.Format(KEY_URL, vt, vid, fiId, filename), Encoding.UTF8);

            json = StringUtility.SubString(json, "QZOutputJson=", ";");

            QQKey keyData = JsonUtility.Object<QQKey>(json);

            return keyData;
        }

        private QQData GetQQData(string vid, string format)
        {
            string json = HttpUtility.Get(string.Format(JSON_URL, vid, format), Encoding.UTF8);

            json = StringUtility.SubString(json, "QZOutputJson=", ";");

            QQData data = JsonUtility.Object<QQData>(json);

            return data;
        }

        private string GetVid(string html)
        {
            string json = StringUtility.SubString(html, "var VIDEO_INFO=", ";");

            VideoInfo info = JsonUtility.Object<VideoInfo>(json);

            return info.Vid;
        }

        private class QQKey
        {
            public int Ct { get; set; }
            public string Key { get; set; }
            public int Level { get; set; }
            public int LevelValid { get; set; }
            public string S { get; set; }
        }

        private class QQData
        {
            public Fl Fl { get; set; }
            public Vl Vl { get; set; }
        }

        private class Fl
        {
            public int Cnt { get; set; }
            public Fi[] Fi { get; set; }
        }

        private class Vl
        {
            public Vi[] Vi { get; set; }
        }

        private class Ul
        {
            public Ui[] Ui { get; set; }
        }

        private class Vi
        {
            public int Br { get; set; }
            public int Ch { get; set; }
            public Cl Cl { get; set; }
            public string Fmd5 { get; set; }
            public string Fn { get; set; }
            public long Fs { get; set; }
            public string Lnk { get; set; }
            public string Ti { get; set; }
            public int Type { get; set; }
            public Ul Ul { get; set; }
            public string Vid { get; set; }
        }

        private class Ui
        {
            public int Dt { get; set; }
            public int Dtc { get; set; }
            public string Url { get; set; }
            public int Vt { get; set; }
        }

        private class Cl
        {
            public Ci[] Ci { get; set; }
            public int Fc { get; set; }
        }


        private class Ci
        {
            public double Cd { get; set; }
            public string Cmd5 { get; set; }
            public int Cs { get; set; }
            public int Idx { get; set; }
        }

        private class Fi
        {
            public int Br { get; set; }
            public int Id { get; set; }
            public string Name { get; set; }
            public int Sl { get; set; }
        }

        private class VideoInfo
        {
            public string Title { get; set; }
            public int Duration { get; set; }
            public string Vid { get; set; }
        }
    }
}
